package captcha

import (
	"encoding/json"
	"fmt"
	"github.com/wenlng/go-captcha-assets/helper"
	"github.com/wenlng/go-captcha-assets/resources/images_v2"
	"github.com/wenlng/go-captcha-assets/resources/tiles"
	"github.com/wenlng/go-captcha/v2/slide"
	"goravel/app/services/captcha/cache"
	"log"
)

// "github.com/wenlng/go-captcha-assets/resources/images_v2"
type CaptchaService struct {
}

func NewCaptchaService() *CaptchaService {
	return &CaptchaService{}
}

var slideBasicCapt slide.Captcha

type Point struct {
	X int `json:"x"`
	Y int `json:"y"`
}

func init() {
	builder := slide.NewBuilder(
		//slide.WithGenGraphNumber(2),
		slide.WithEnableGraphVerticalRandom(true),
	)

	// background images
	imgs, err := images.GetImages()
	if err != nil {
		log.Fatalln(err)
	}

	graphs, err := tiles.GetTiles()
	if err != nil {
		log.Fatalln(err)
	}

	var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
	for i := 0; i < len(graphs); i++ {
		graph := graphs[i]
		newGraphs = append(newGraphs, &slide.GraphImage{
			OverlayImage: graph.OverlayImage,
			MaskImage:    graph.MaskImage,
			ShadowImage:  graph.ShadowImage,
		})
	}

	// set resources
	builder.SetResources(
		slide.WithGraphImages(newGraphs),
		slide.WithBackgrounds(imgs),
	)

	slideBasicCapt = builder.Make()
}

// GetSlideBasicCaptData .
func (c *CaptchaService) GetSlideBasicCaptData() map[string]interface{} {
	captData, err := slideBasicCapt.Generate()
	if err != nil {
		log.Fatalln(err)
	}

	blockData := captData.GetData()
	if blockData == nil {
		return map[string]interface{}{
			"code":    1,
			"message": "gen captcha data failed",
		}
	}

	var masterImageBase64, tileImageBase64 string
	masterImageBase64, err = captData.GetMasterImage().ToBase64()
	if err != nil {
		return map[string]interface{}{
			"code":    1,
			"message": "base64 data failed",
		}
	}

	tileImageBase64, err = captData.GetTileImage().ToBase64()
	if err != nil {
		return map[string]interface{}{
			"code":    1,
			"message": "base64 data failed",
		}
	}

	dotsByte, _ := json.Marshal(blockData)
	key := helper.StringToMD5(string(dotsByte))
	cache.WriteCache(key, dotsByte)

	bt := map[string]interface{}{
		"code":         0,
		"captcha_key":  key,
		"image_base64": masterImageBase64,
		"tile_base64":  tileImageBase64,
		"tile_width":   blockData.Width,
		"tile_height":  blockData.Height,
		"tile_x":       blockData.TileX,
		"tile_y":       blockData.TileY,
	}
	return bt
}

// CheckSlideData .
func (c *CaptchaService) CheckSlideData(key string, point Point) (int, bool, error) {
	code := 1

	cacheDataByte := cache.ReadCache(key)
	if len(cacheDataByte) == 0 {
		return code, false, fmt.Errorf("has no cache data")
	}

	var dct *slide.Block
	if err := json.Unmarshal(cacheDataByte, &dct); err != nil {
		return code, false, fmt.Errorf("illegal key")
	}

	chkRet := false
	chkRet = slide.CheckPoint(int64(point.X), int64(point.Y), int64(dct.X), int64(dct.Y), 2)

	if chkRet {
		code = 0
	}

	return code, true, nil
}
